package com.huai.jt1078.handler;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.huai.jt1078.entity.VisualAudio;
import com.huai.jt1078.enums.DataType;
import com.huai.jt1078.enums.VisualAudioType;
import com.huai.jt1078.handler.video.VisualAudioHandler;
import com.huai.jt1078.utils.SessionManager;
import com.huai.jt1078.utils.VideoUtil;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * @author xingkong
 * @program jt1078
 * @description 消息处理类
 * @date 2021-09-06 15:53
 **/
@ChannelHandler.Sharable
@Slf4j
@Component
public class MessageHandler extends SimpleChannelInboundHandler<VisualAudio> {

    private final Map<String, VisualAudioHandler> visualAudioHandlers;

    public MessageHandler(Map<String, VisualAudioHandler> visualAudioHandlers) {
        this.visualAudioHandlers = visualAudioHandlers;
    }


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, VisualAudio visualAudio) throws Exception {
        VisualAudioHandler visualAudioHandler = null;
        // 判断数据类型 视频还是音频
        if (DataType.getVideoTypes().contains(visualAudio.getDataType())){
            visualAudioHandler = visualAudioHandlers.get(VisualAudioType.VIDEO.getClassName());
        } else if(DataType.AUDIO.getType().equals(visualAudio.getDataType())){
            visualAudioHandler = visualAudioHandlers.get(VisualAudioType.AUDIO.getClassName());
        }
        // 如果匹配到数据类型 则执行逻辑处理
        if (ObjectUtil.isNotNull(visualAudioHandler)){
            visualAudioHandler.handler(visualAudio,ctx);
        }
    }

    /**
     * 通道被激活时
     * @param ctx 上下文
     * @author xingkong
     * @date 2021-09-06 15:57
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        release(ctx);
    }

    /**
     * 触发用户事件 如 没有收到心跳（认为已经断线了）
     * @param ctx 上下文
     * @author xingkong
     * @date 2021-09-06 15:57
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                log.error("channel time out:{}",SessionManager.instance.getChannelTagMap().get(ctx));
                release(ctx);
            }
        }
    }

    /**
     * 异常捕获
     * @param ctx 上下文
     * @param cause  异常信息
     * @author xingkong
     * @date 2021-09-06 17:33
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        release(ctx);
    }


    /**
     * 重置通道
     * @param channel 通道
     * @author xingkong
     * @date 2021-09-06 17:45
     */
    private static void release(ChannelHandlerContext channel){
        channel.close();
        String tag = SessionManager.instance.getChannelTagMap().get(channel);
        SessionManager.instance.getChannelTagMap().remove(channel);
        if (StrUtil.isNotBlank(tag)){
            log.info("-----------释放通道：{}-----------",tag);
            SessionManager.instance.getTagChannelMap().remove(tag);

            // 销毁工具类
            VideoUtil videoUtil = SessionManager.instance.getVideoUtils().get(tag);
            if (null != videoUtil){
                videoUtil.close();
            }
            SessionManager.instance.getVideoUtils().remove(tag);

            // 关闭目标通道
            ChannelHandlerContext targetContext = SessionManager.instance.getTargetTagChannelMap().get(tag);
            if (null != targetContext){
                targetContext.close();
            }
            SessionManager.instance.getTargetTagChannelMap().remove(tag);

            // 关闭websocket工具类
            SessionManager.instance.getWebsocketUtilMap().remove(tag);


            // 销毁线程
            Process process = SessionManager.instance.getProcessMap().get(tag);
            SessionManager.instance.getProcessMap().remove(tag);
            if (null != process){
               try {
                   process.destroy();
               }catch (Exception e){
                   log.error("销毁推送线程失败:",e);
               }
            }
        }
    }
}
